
var MyActor = require('./my_actor');

function* recursionRun(self, id, name) {
    for (let i = 0; i < 3; i++) {
        yield self.yield_sleep(100);
        MyActor.trace_space("recursionRun", id, name, i);
    }
    return ["recursionRun result", id, name];
}

var go = MyActor.create(function* (self) {
    for (let i = 0; i < 3; i++) {
        MyActor.trace_space("rec invoke", yield* recursionRun(self, i, "yield*"));
        yield self.yield_sleep(100);
        MyActor.trace_space("rec invoke", yield recursionRun(self, i, "yield"));
    }
});

var notify_test = MyActor.create(function* (self) {
    let notify_handle = self.make_notify_handle();
    let ntf = self.make_notify(notify_handle);
    ntf(1);
    setTimeout(function () {
        ntf(2);
    }, 100);
    MyActor.trace_space(yield self.yield_wait_many_notify(notify_handle, 2));
});

var trig_test = MyActor.create(function* (self) {
    let trig_handle = self.make_trig_handle();
    let ntf = self.make_trig(trig_handle);
    setTimeout(function () {
        ntf(2);
    }, 100);
    MyActor.trace_space(yield self.yield_wait_trig(trig_handle));
});

var msg_test = MyActor.create(function* (self) {
    let sum = 0;
    let child = self.create_child(function* (self) {
        let child1 = self.create_child(function* (self) {
            for (let i = 0; i < 3; i++) {
                let msg = yield self.yield_wait_msg("int");
                sum += msg.value;
                msg.reply("ok");
            }
            return sum;
        }).run();
        yield self.yield_sleep(10);
        self.msg_agent_to("int", child1);
        yield self.yield_wait_quit(child1);
        return sum;
    }).run();
    for (let i = 0; i < 3; i++) {
        yield self.yield_sleep(100);
        MyActor.trace_space(yield self.yield_send_msg(child, "int", i));
    }
    yield self.yield_wait_quit(child);
    MyActor.trace_space(sum);
});

var csp_test = MyActor.create(function* (self) {
    let csp = self.make_csp_handle();
    let child = self.create_child(function* (self) {
        while (true) {
            yield self.yield_wait_csp(csp, function* (arg) {
                MyActor.trace_space("csp msg", arg);
                yield self.yield_sleep(100);
                return arg+100;
            })
        }
    }).run();
    for (let i = 0; i < 3; i++) {
        yield self.yield_sleep(100);
        MyActor.trace_space("csp result", yield self.yield_csp_invoke(csp, i));
    }
    yield self.yield_children_force_quit();
});

var mutex_test = MyActor.create(function* (self) {
    let mutex = self.make_mutex();
    let child1 = self.create_child(function* (self) {
        for (let i = 0; i < 3; i++) {
            yield self.yield_sleep(10);
            yield mutex.yield_lock();
            MyActor.trace_space("child1 0");
            yield self.yield_sleep(100);
            MyActor.trace_space("child1 1");
            yield self.yield_sleep(100);
            MyActor.trace_space("child1 2");
            yield self.yield_sleep(100);
            mutex.unlock();
        }
    }).run();
    let child2 = self.create_child(function* (self) {
        for (let i = 0; i < 3; i++) {
            yield self.yield_sleep(20);
            yield mutex.yield_lock();
            MyActor.trace_space("child2 0");
            yield self.yield_sleep(100);
            MyActor.trace_space("child2 1");
            yield self.yield_sleep(100);
            MyActor.trace_space("child2 2");
            yield self.yield_sleep(100);
            mutex.unlock();
        }
    }).run();
    yield self.yield_wait_quit(child1, child2);
});

var convar_test = MyActor.create(function *(self) {
    let mutex = self.make_mutex();
    let convar = self.make_condition_variable();
    let sign = false;
    let over = false;
    let child1 = self.create_child(function* (self){
        for (let i = 0; i < 3; i++) {
            yield self.yield_sleep(500);
            yield self.yield_lock_guard(mutex, function* () {
                yield self.yield_sleep(500);
                sign = true;
                MyActor.trace_space("wait notify");
                yield convar.yield_wait(mutex);
                MyActor.trace_space("notifed");
            });
        }
        yield mutex.yield_lock();
        over = true;
        mutex.unlock();
    }).run();
    let child2 = self.create_child(function* (self){
        let check = true;
        while (check) {
            yield self.yield_sleep(600);
            yield self.yield_lock_guard(mutex, function* () {
                if (!over) {
                    if (sign) {
                        sign = false;
                        convar.notify_one();
                    }
                } else {
                    check = false;
                }
            });
        }
    }).run();
    yield self.yield_wait_quit(child1, child2);
});

var channel_test = MyActor.create(function* (self) {
    let channel = self.make_channel_handle();
    self.create_child(function* (self) {
        for (let i = 0; i < 3; i++) {
            yield self.yield_channel_push(channel, i);
            yield self.yield_sleep(300);
        }
    }).run();
    self.create_child(function* (self) {
        for (let i = 0; i < 3; i++) {
            let [, msg] = yield self.yield_channel_pop(channel);
            MyActor.trace_space(msg);
            yield self.yield_sleep(100);
        }
    }).run();
});

var shared_mutex_test = MyActor.create(function* (self) {
    let smtx = self.make_shared_mutex();
    let ch1 = self.create_child(function* (self) {
        for (let i = 0; i < 10; i++) {
            MyActor.trace_space(self.self_id(), "A-", "mutex in");
            yield self.yield_lock_guard(smtx, function* () {
                MyActor.trace_space(self.self_id(), "A-", ">mutex in");
                MyActor.trace_space(self.self_id(), "A-", i, 0);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A-", i, 1);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A-", i, 2);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A-", "mutex out");
            });
            yield self.yield_sleep(10);
        }
    }).run();
    let ch2 = self.create_child(function* (self) {
        for (let i = 0; i < 10; i++) {
            MyActor.trace_space(self.self_id(), "A+", "mutex in");
            yield self.yield_lock_guard(smtx, function* () {
                MyActor.trace_space(self.self_id(), "A+", ">mutex in");
                MyActor.trace_space(self.self_id(), "A+", i, 0);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", i, 1);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", i, 2);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", i, 3);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", i, 4);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", i, 5);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "A+", "mutex out");
            });
            yield self.yield_sleep(10);
        }
    }).run();
    let ch3 = self.create_child(function* (self) {
        for (let i = 0; i < 10; i++) {
            MyActor.trace_space(self.self_id(), "B", "shared_mutex in");
            yield self.yield_pess_shared_guard(smtx, function* () {
                MyActor.trace_space(self.self_id(), "B", ">shared_mutex in");
                MyActor.trace_space(self.self_id(), "B", i, 0);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B", i, 1);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B", i, 2);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B-", "--upgrade_mutex in");
                yield self.yield_upgrade_guard(smtx, function* () {
                    MyActor.trace_space(self.self_id(), "B-", ">--upgrade_mutex in");
                    MyActor.trace_space(self.self_id(), "B-", i, 3);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "B-", i, 4);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "B-", i, 5);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "B-", i, 6);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "B-", "-upgrade_mutex out");
                });
                MyActor.trace_space(self.self_id(), "B-", ">-upgrade_mutex out");
                MyActor.trace_space(self.self_id(), "B", i, 7);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B", i, 8);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B", i, 9);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "B", "shared_mutex out");
            });
            yield self.yield_sleep(10);
        }
    }).run();
    let ch4 = self.create_child(function* (self) {
        for (let i = 0; i < 10; i++) {
            MyActor.trace_space(self.self_id(), "C", "shared_mutex in");
            yield self.yield_pess_shared_guard(smtx, function* () {
                MyActor.trace_space(self.self_id(), "C", ">shared_mutex in");
                MyActor.trace_space(self.self_id(), "C", i, 0);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", i, 1);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C-", "--upgrade_mutex in");
                yield self.yield_upgrade_guard(smtx, function* () {
                    MyActor.trace_space(self.self_id(), "C-", ">--upgrade_mutex in");
                    MyActor.trace_space(self.self_id(), "C-", i, 2);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "C-", i, 3);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "C-", i, 4);
                    yield self.yield_sleep(10);
                    MyActor.trace_space(self.self_id(), "C-", "-upgrade_mutex out");
                });
                MyActor.trace_space(self.self_id(), "C-", ">-upgrade_mutex out");
                MyActor.trace_space(self.self_id(), "C", i, 5);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", i, 6);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", i, 7);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", i, 8);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", i, 9);
                yield self.yield_sleep(10);
                MyActor.trace_space(self.self_id(), "C", "shared_mutex out");
            });
            yield self.yield_sleep(10);
        }
    }).run();
    yield self.yield_wait_quit(ch1, ch2, ch3, ch4);
    MyActor.trace_space("end");
});

var suspend_test = MyActor.create(function* (self) {
    let child = self.create_child(function* (self) {
        let child = self.create_child(function* (self) {
            let i = 0;
            yield self.yield_sleep(300);
            MyActor.trace_space("---child2", i++);
            MyActor.trace_space("---lock suspend");
            self.lock_suspend();
            for (let j = 0; j < 10; j++)
            {
                yield self.yield_sleep(100);
                MyActor.trace_space("---child2", i++);
            }
            MyActor.trace_space("---begin unlock suspend");
            yield self.yield_unlock_suspend();
            MyActor.trace_space("---end unlock suspend");
            MyActor.trace_space("---child2", i++);
            yield self.yield_sleep(100);
        }).run();
        let i = 0;
        yield self.yield_sleep(100);
        MyActor.trace_space("--child1", i++);
        yield self.yield_sleep(300);
        MyActor.trace_space("--child1", i++);
        yield self.yield_sleep(300);
        MyActor.trace_space("--child1", i++);
        yield self.yield_wait_quit(child);
    }).run();
    yield self.yield_sleep(500);
    MyActor.trace_space("-begin suspend");
    yield self.yield_suspend(child);
    MyActor.trace_space("-end suspend");
    yield self.yield_sleep(1500);
    MyActor.trace_space("-begin resume");
    yield self.yield_resume(child);
    MyActor.trace_space("-end resume");
    yield self.yield_wait_quit(child);
});

var select_msg = MyActor.create(function* (self) {
    let notify_handle = self.make_notify_handle();
    let trig_handle = self.make_trig_handle();
    let csp_handle = self.make_csp_handle();
    let channel = self.make_channel_handle();
    let child = self.create_child(function* (self) {
        self.lock_quit();
        yield self.yield_select_msg(notify_handle, function* (msg) {
            MyActor.trace_space("notify", msg);
            yield self.yield_sleep(10);
        }, trig_handle, function* (msg) {
            MyActor.trace_space("trig", msg);
            yield self.yield_sleep(10);
        }, csp_handle, function* (reply, [msg]) {
            MyActor.trace_space("csp", msg);
            yield self.yield_sleep(10);
            reply("csp result");
        }, self.get_msg_handle("msg1"), function* (msg) {
            MyActor.trace_space("actor", msg);
            yield self.yield_sleep(10);
        }, channel, function* (state, msg) {
            MyActor.trace_space("channel", msg);
        }, self.get_quit_handle(), function* () {
            MyActor.trace_space("quit msg");
            return true;
        });
        yield self.yield_unlock_quit();
    }).run();
    let ntf1 = child.make_notify(notify_handle);
    let trig1 = child.make_trig(trig_handle);
    for (let i = 0; i < 3; i++) {
        yield self.yield_sleep(100);
        ntf1(["notify", i]);
        yield self.yield_sleep(100);
        child.post_msg("msg1", ["msg", i]);
        MyActor.trace_space(yield csp_handle.yield_invoke(i));
        yield self.yield_sleep(100);
        yield channel.yield_push(i);
    }
    trig1(["trig", "msg"]);
    yield self.yield_sleep(500);
    child.force_quit();
    yield self.yield_wait_quit(child);
});

var perfor_test = MyActor.create(function* (self) {
    yield self.yield_sleep(100);
    let count = 0;
    for (let i = 0; i < 100; i++) {
        self.create_child(function*(self) {
            while (true) {
                count++;
                yield self.yield_tick();
            }
        }).run();
    }
   for (let i = 0; i < 10; i++) {
        yield self.yield_sleep(1000);
        MyActor.trace_space(count);
        count = 0;
    }
    yield self.yield_children_force_quit();
});

var leak_test = MyActor.create(function *(self) {
    while (true) {
        let ct = 0;
        let child = self.create_child(function *(self) {
            let rcPool = MyActor.create_list();
            self.append_quited_exec(function () {
                //rcPool.clear();
            });
            while (true) {
                ct++;
                rcPool.push_back(ct.toString());
                yield self.yield_tick();
            }
        }).run();
        yield self.yield_sleep(3000);
        yield self.yield_children_force_quit();
        MyActor.trace_space(ct);
    }
});

var test = MyActor.create(function* (self) {
    go.run();
    yield self.yield_wait_quit(go);
    notify_test.run();
    yield self.yield_wait_quit(notify_test);
    trig_test.run();
    yield self.yield_wait_quit(trig_test);
    msg_test.run();
    yield self.yield_wait_quit(msg_test);
    csp_test.run();
    yield self.yield_wait_quit(csp_test);
    channel_test.run();
    yield self.yield_wait_quit(channel_test);
    mutex_test.run();
    yield self.yield_wait_quit(mutex_test);
    convar_test.run();
    yield self.yield_wait_quit(convar_test);
    suspend_test.run();
    yield self.yield_wait_quit(suspend_test);
    select_msg.run();
    yield self.yield_wait_quit(select_msg);
    shared_mutex_test.run();
    yield self.yield_wait_quit(shared_mutex_test);
    perfor_test.run();
    yield self.yield_wait_quit(perfor_test);
    leak_test.run();
    yield self.yield_wait_quit(leak_test);
});
test.run();

var net = require('net');
var server = net.createServer();
server.listen(3000);

var session = function* (self, client) {
    MyActor.trace_space("new session");
    let read = self.create_child(function* (self) {
        let lstMsg = self.make_notify_handle();
        client.on("data", self.make_notify(lstMsg));
        while (true) {
            MyActor.trace_space((yield self.yield_wait_notify(lstMsg)).value.toString());
            let sendStr = (new Date()).toTimeString()+"\n";
            for (let i = 0; i < sendStr.length; i++) {
                client.write(sendStr.charAt(i));
                yield self.yield_sleep(100);
            }
        }
    }).run();
    yield client.on("end", self.make_asio_context());
    yield self.yield_force_quit(read);
    MyActor.trace_space("close session");
};

MyActor.create(function* (self) {
    let lstConnect = self.make_notify_handle();
    server.on("connection", self.make_notify(lstConnect));
    while (true) {
        MyActor.create(MyActor.bind(session, (yield self.yield_wait_notify(lstConnect)).value)).run();
    }
}).run();
